package com.hd.trans.network.component

import android.app.AlertDialog
import android.content.Context
import android.os.Handler
import android.text.TextUtils
import android.util.Log
import android.util.SparseArray
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.hd.trans.R
import com.hd.trans.TranslationInterior
import com.hd.trans.common.Constants
import com.hd.trans.framework.tools.ThreadPoolWrapper
import com.hd.trans.network.ApiServiceManager
import com.hd.trans.network.MultNetDisposableObserver
import com.hd.trans.network.RxSchedulers
import com.hd.trans.network.bean.MultDataResponse2
import com.hd.trans.network.bean.trans.BaseResponse
import com.hd.trans.network.bean.trans.MessageRes
import com.hd.trans.network.bean.trans.QueryTaskStatus
import com.hd.trans.network.bean.trans.TextTransNewReq
import com.hd.trans.network.bean.trans.TextTransNewRes
import com.hd.trans.network.bean.trans.UploadTaskStatus
import com.hd.trans.share.Md5Util
import com.hd.trans.share.UrlDownloadRequest
import com.hd.trans.ui.base.AppContextProvider
import com.hd.trans.ui.service.NetDisposableObserver3
import com.hd.trans.utils.Base64Util.imageToBase64
import com.hd.trans.utils.CommonUtil
import com.hd.trans.utils.FileTranslationUtil
import com.hd.trans.utils.OfflineConstant
import com.hd.trans.utils.PhotoFileUtil
import com.hd.trans.utils.StringUtils
import com.hd.trans.utils.ToastUtils
import io.reactivex.Observable
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.File
import java.util.TreeMap


/**
 * 文档翻译组件
 * 支持的文件格式包括：txt,doc,docx,ppt,pptx,pdf,xls,xlsx
 * 图片翻译组件
 * 支持图片格式：jpg,png,jpeg,webp
 */
class FileTranslateManager: FileTranslateComponent, LifecycleObserver {

    private var progressValue: Int = 0
    private var isCancel: Boolean = false
    private var call: Call<String>? = null
    private var splitBase64List: ArrayList<String>? = null
    private var fileTranslateCallback: FileTranslateCallback? = null
    private var textTranslateCallback: TextTranslateCallback? = null
    private var fileTranslateListener: FileTranslateListener? = null
    private val mHandler: Handler = Handler()
    private val delayMill: Long = 1000//可根据上传文件大小修改查询间隔时间
    private var radix: Int = 1//delayMill系数
    private var taskId: String? = null
    private var queryTaskCount = 0//查询次数统计
    private var isDestroy = false
    private var productId = TranslationInterior.getProductIdInteger()
    private var userId = ""

    /**
     * 页面销毁 终止回调
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy() {
        isDestroy = true
        //
    }

    fun setFileTranslateCallback(fileTranslateCallback: FileTranslateCallback){
        this.fileTranslateCallback = fileTranslateCallback
    }

    fun setFileTranslateCallback(fileTranslateListener: FileTranslateListener){
        this.fileTranslateListener = fileTranslateListener
    }

    fun setProductInfo(productId: Int, userId: String){
        this.productId = productId
        this.userId = userId
    }

    fun setTextTranslateCallback(textTranslateCallback: TextTranslateCallback){
        this.textTranslateCallback = textTranslateCallback
    }

    fun fileTranslate(
        fromLang: String,
        toLang: String,
        filePath: String,
        imageTextLayout: String = "auto",
        imageScale: Int = 1,
        imageFontSize: Int = 0,
        password: String = ""
    ) {
        if(!File(filePath).exists()){
            fileTranslateCallback?.onTranslateFailed(0,"文件不存在")
            fileTranslateListener?.onTranslateFailed(0,"文件不存在")
            return
        }
        if(FileTranslationUtil.isTxt(filePath)){
            //检测文本文件
            if(File(filePath).length() == 0L){
                fileTranslateCallback?.onTranslateFailed(0,"文本内容为空")
                fileTranslateListener?.onTranslateFailed(0,"文本内容为空")
                return
            }
        }else{
            //检测非文本文件
            if(File(filePath).length() < 30){
                fileTranslateCallback?.onTranslateFailed(0,"文档已损坏")
                fileTranslateListener?.onTranslateFailed(0,"文档已损坏")
                return
            }
        }
        if(!FileTranslationUtil.isSupportedFormat(filePath)){
            fileTranslateCallback?.onTranslateFailed(0,"不支持的文件格式")
            fileTranslateListener?.onTranslateFailed(0,"不支持的文件格式")
            return
        }
        isCancel = false
        //开始文档翻译
        fileTranslateCallback?.startTranslate()
        createTask({ id ->
            if(isCancel) return@createTask
            //请求任务完成
            this.taskId = id
            fileTranslateCallback?.onTaskId(id)
            fileTranslateListener?.onTranslateStart(id)

            uploadFile(
                fromLang,
                toLang,
                id,
                filePath,
                imageTextLayout,
                imageScale,
                imageFontSize,
                FileTranslationUtil.isFileNeedSharded(filePath),
                password,
            ){
                //上传文件完成
                queryTaskCount = 0
                radix = 1
                progressValue = 0
                mHandler.removeCallbacks(queryTaskRunnable)
                mHandler.postDelayed(queryTaskRunnable, (delayMill*radix).toLong())
            }
        },{
            fileTranslateCallback?.onTranslateFailed(0,"创建任务失败")
            fileTranslateListener?.onTranslateFailed(0,"创建任务失败")
        })
    }

    private fun uploadNextSplit(aBack: () -> Unit){
        if(splitBase64List == null || splitBase64List!!.size == 0) {
            aBack.invoke()
            return
        }
        val data = splitBase64List?.removeFirst()
        if(taskId == null || data == null) return

        uploadSplit(taskId!!, data){ status, id ->
            if(id == taskId){
                if(status){
                    uploadNextSplit(aBack)
                }else{
                    fileTranslateCallback?.onTranslateFailed(0,"文档分片上传失败")
                    fileTranslateListener?.onTranslateFailed(0,"文档分片上传失败")
                }
            }
        }
    }


    override fun fileTranslate(
        fromLang: String,
        toLang: String,
        filePath: String,
    ) {
        fileTranslate(fromLang,toLang,filePath,"auto",1,0, "")
    }

    fun fileTranslate(
        fromLang: String,
        toLang: String,
        filePath: String,
        password: String
    ) {
        fileTranslate(fromLang,toLang,filePath,"auto",1,0, password)
    }

    /**创建任务*/
    private fun createTask(aBack:((taskId: String)->Unit)?,bBack:(()->Unit)?) {
        call = ApiServiceManager.transitionNewApi.createTask()

        //发送网络请求(异步)
        call?.enqueue(
            object : Callback<String?> {
                //请求成功时回调
                override fun onResponse(call: Call<String?>, response: Response<String?>) {
                    //ToastUtils.showInfo("任务创建成功")
                    response.body()?.let {
                        aBack?.invoke(it)
                    }
                }

                //请求失败时回调
                override fun onFailure(call: Call<String?>, t: Throwable) {
                    if(t.message?.contains("Canceled") == true){
                        //任务被人为取消了
                        return
                    }
                    bBack?.invoke()
                }
            }
        )
    }

    /**
     * 分片上传
     */
    private fun uploadSplit(taskId: String, data: String, bBack: ((Boolean, String) -> Unit)?){
        ApiServiceManager.transitionNewApi.writeBigFileTask(
            taskId,
            data
        ).compose(RxSchedulers.applySchedulers())
            .subscribe(NetDisposableObserver3(object :
                NetDisposableObserver3.NetCallBack<MessageRes> {
                override fun onResponse(response: MessageRes) {
                    bBack?.invoke(response.isStatus, taskId)
                }

                override fun onError(code: Int, msg: String) {
                    bBack?.invoke(false, taskId)
                }

                override fun onTokenInvalid(msg: String) {
                    bBack?.invoke(false, taskId)
                }
            }))
    }

    /**上传文档*/
    private fun uploadFile(
        fromLang: String,
        toLang: String,
        taskId: String,
        filePath: String,
        imageTextLayout: String,
        imageScale: Int,
        imageFontSize: Int,
        isBigFile: Boolean,
        password: String,
        back: (() -> Unit)?,
    ) {
        splitBase64List?.clear()
        if(isBigFile) {
            //文档过大，需要分片处理
            splitBase64List = FileTranslationUtil.splitFile2Base64(File(filePath))
        }
        uploadNextSplit(){
            ApiServiceManager.transitionNewApi.uploadTaskNew(
                fromLang,
                toLang,
                taskId,
                File(filePath).name,
                if(isBigFile) "" else imageToBase64(filePath),
                imageTextLayout,
                imageScale,
                imageFontSize,
                isBigFile,
                productId,
                userId,
                password
            ).compose(RxSchedulers.applySchedulers())
                .subscribe(NetDisposableObserver3(object :
                    NetDisposableObserver3.NetCallBack<BaseResponse<UploadTaskStatus>> {
                    override fun onResponse(response: BaseResponse<UploadTaskStatus>) {
                        if (response != null) {
                            back?.invoke()
                        }
                    }

                    override fun onError(code: Int, msg: String) {
                    }

                    override fun onTokenInvalid(msg: String) {
                    }
                }))
        }
    }

    /**翻译任务进度查询*/
    private fun queryTask(back:((status:QueryTaskStatus)->Unit)?) {
        ApiServiceManager.transitionNewApi.queryTaskEx(taskId)
            .compose(RxSchedulers.applySchedulers())
            //错误处理
            .onErrorResumeNext(Function<Throwable, Observable<BaseResponse<QueryTaskStatus>>> { throwable ->
                Log.e("FileTranslateManager1", "queryTask error = ${throwable.message}")
                Observable.just(BaseResponse<QueryTaskStatus>().apply {
                    data = QueryTaskStatus()
                    data.taskStatus = "pending"
                    isStatus = false
                })
            })
            .subscribe(NetDisposableObserver3(object :
                NetDisposableObserver3.NetCallBack<BaseResponse<QueryTaskStatus>> {
                override fun onResponse(response: BaseResponse<QueryTaskStatus>) {
                    if (response != null) {
                        response.data?.let {
                            if(it.taskStatus == "error"){
                                if(it.isDanger){
                                    fileTranslateCallback?.onTranslateFailed(Constants.ResponseCode.ERROR_IS_DANGER,"翻译失败")
                                    fileTranslateListener?.onTranslateFailed(Constants.ResponseCode.ERROR_IS_DANGER,"翻译失败")
                                }else{
                                    fileTranslateCallback?.onTranslateFailed(0,"翻译失败")
                                    fileTranslateListener?.onTranslateFailed(0,"翻译失败")
                                }
                                return
                            }
                            fileTranslateCallback?.onTaskStatus(it.taskStatus,it.estimatedTime,it.pendingCount, progressValue)
                            if(progressValue < 99){
                                if(it.progress > progressValue){
                                    progressValue = it.progress
                                }else{
                                    progressValue += 1//让进度条动起来！
                                }
                            }
                            if (it.progress == 100) {
                                fileTranslateCallback?.onTaskStatus(it.taskStatus,it.estimatedTime,it.pendingCount, 100)
                                back?.invoke(response.data)
                            } else {
                                mHandler.removeCallbacks(queryTaskRunnable)
                                mHandler.postDelayed(
                                    queryTaskRunnable,
                                    (delayMill*radix).toLong()
                                )
                            }
                        }
                    }
                }

                override fun onError(code: Int, msg: String) {
                    if(code == 110){// 正常反馈，但是解析失败。后端任务已满，任务进入pending等待状态
                        mHandler.removeCallbacks(queryTaskRunnable)
                        mHandler.postDelayed(
                            queryTaskRunnable,
                            (delayMill*radix).toLong()
                        )
                    }
                }

                override fun onTokenInvalid(msg: String) {
                }
            }))
    }

    fun cancelQueryTask(){
        isCancel = true
        call?.cancel()
        taskId = null
        mHandler.removeCallbacks(queryTaskRunnable)
    }

    private val queryTaskRunnable = Runnable {
        queryTaskCount ++
        if(queryTaskCount >= 10){
            //每超过10次，每次延迟请求多+1秒
            radix = queryTaskCount / 10
        }

        if (taskId == null/* || queryTaskCount > 200*/) {//总时长为1100秒
            //fileTranslateCallback?.onTranslateFailed(NetCode.STATE_ERROR_TIME_OUT,"请求超时")
            //fileTranslateListener?.onTranslateFailed(NetCode.STATE_ERROR_TIME_OUT,"请求超时")
            return@Runnable
        }
        queryTask{ q ->
            if(q.taskStatus == "success"){
                fileTranslateCallback?.let {
                    it.onTranslateCompleted(q.srcText, q.dstText,null,null,true)
                    val urls = arrayListOf<String>()
                    add2List(urls, q.dstDownload)
                    add2List(urls, q.untrans)
                    add2List(urls, q.trans)
                    add2List(urls, q.inpainted)
                    add2List(urls, q.meta)
                    //下载文件
                    downloadFile(taskId, urls, it)
                }

                fileTranslateListener?.onTranslateCompleted(q.taskId, q)

            }else{
                if(q.isDanger){
                    fileTranslateCallback?.onTranslateFailed(Constants.ResponseCode.ERROR_IS_DANGER,"翻译失败")
                    fileTranslateListener?.onTranslateFailed(Constants.ResponseCode.ERROR_IS_DANGER,"翻译失败")
                }else{
                    fileTranslateCallback?.onTranslateFailed(0,"翻译失败")
                    fileTranslateListener?.onTranslateFailed(0,"翻译失败")
                }
            }
        }
    }

    private fun add2List(list: ArrayList<String>, str: String?){
        if(!TextUtils.isEmpty(str)){
            list.add(str!!)
        }
    }

    /**下载翻译文件*/
    private fun downloadFile(taskId: String?,urls: List<String>, downloadCallback: FileTranslateCallback?) {

        val sveNames = arrayListOf<String>()
        urls.forEach {
            val dstDownloadPath: String = it
            val saveName = dstDownloadPath.substring(dstDownloadPath.lastIndexOf("/") + 1)
            //荣耀文档浏览器不支持文件路径中有?
            val docFilePath = PhotoFileUtil.getPhotoDownloadPath() + saveName.replace("?", "")
            sveNames.add(docFilePath)
        }
        // 删除缓存的文件
        //FileUtils.clearFolderSubFiles(File(docFilePath).parentFile)
        val downloadThread = UrlDownloadRequest(taskId, urls, sveNames)

        fileTranslateCallback?.onTaskStatus("downloading",0,0)
        ThreadPoolWrapper.getInstance().excuseThread{
            downloadThread.downloadFile(downloadCallback)
        }
    }

    /**文本翻译*/
    fun textTranslate(originalText: String, fromLang: String, toLang: String, withDiff: Boolean = false) {
        val req = TextTransNewReq()
        req.fromLang = fromLang
        req.toLang = toLang
        req.fromText = originalText
        req.fromProduct = "sdk"
        req.withDiff = withDiff
        textTranslateCallback?.startTranslate()
        ApiServiceManager.transitionNewApi
            .tansText(req)
            .compose(RxSchedulers.applySchedulers())
            .subscribe(NetDisposableObserver3(object :
                NetDisposableObserver3.NetCallBack<TextTransNewRes> {
                override fun onResponse(response: TextTransNewRes) {
                    if (response != null) {
                        textTranslateCallback?.onTranslateCompleted(
                            response.toText,
                            response.fromLang,
                            response.toLang,
                            response.isStatus
                        )
                    }
                }

                override fun onError(code: Int, msg: String) {
                    textTranslateCallback?.onTranslateFailed(code, msg)
                }

                override fun onTokenInvalid(msg: String) {
                }
            }))
    }

    /**文本快捷翻译*/
    fun textTranslateQuick(context: Context? = null, originalText: String, fromLang: String, toLang: String, withDiff: Boolean = false) {
        val contentList = StringUtils.splitStringByLength(originalText, Constants.MAX_TRANSLATE_SIZE)
        if (contentList != null && contentList.isNotEmpty()) {
            if (context != null && OfflineConstant.checkNetwork(AppContextProvider.getContext()) == OfflineConstant.NETWORL_NONE) {
                AlertDialog.Builder(context).setTitle(R.string.prompt)
                    .setMessage(R.string.no_network_prompt)
                    .setPositiveButton(R.string.str_ok) { dialog, which ->
                        //
                    }
                    .setNegativeButton(R.string.str_cancel) { dialog, which ->
                        //
                    }
                    .create()
                    .show()
                textTranslateCallback?.onTranslateFailed(
                    1000, AppContextProvider.getContext().resources.getString(R.string.no_network_prompt)
                )
                return
            }

            val size = contentList.size
            val observables: Array<Observable<*>?> = arrayOfNulls(size)
            textTranslateCallback?.startTranslate()
            for (i in contentList.indices) {
                val req = TextTransNewReq()
                req.fromLang = fromLang
                req.toLang = toLang
                req.fromText = contentList[i]
                req.timestamp = CommonUtil.getServiceTimeStamp()
                req.withDiff = withDiff
                req.sign = sortByKey(req)
                observables[i] = ApiServiceManager.transitionNewApi
                    .tansTextQuick(req)
                    .map(Function { data: TextTransNewRes? ->
                        MultDataResponse2(
                            i.toString(),
                            data
                        )
                    } as Function<TextTransNewRes?, MultDataResponse2>)
            }

            var fromLang: String? = null
            var toLang: String? = null
            Observable.mergeArray(*observables)
                .subscribeOn(Schedulers.io())
                .compose(RxSchedulers.applySchedulers())
                .subscribe(MultNetDisposableObserver(object :
                    MultNetDisposableObserver.NetCallBack {
                    private val stringMap = SparseArray<TextTransNewRes>()
                    override fun onResponse(response: Any) {
                        if (response is MultDataResponse2) {
                            val index = StringUtils.toInt(response.requestTag, -1)
                            val resp = response.dataResponse as TextTransNewRes
                            if (index != -1) {
                                stringMap.put(index, resp)
                                fromLang = resp.fromLang
                                toLang = resp.toLang
                            }
                        }
                    }

                    override fun onError(code: Int, msg: String) {
                        textTranslateCallback?.onTranslateFailed(code, msg)
                    }

                    override fun onTokenInvalid(msg: String) {
                        if (!isDestroy) {
                            textTranslateCallback?.onTranslateFailed(Constants.ResponseCode.ERROR_TOKEN, msg)
                        }
                    }

                    override fun onComplete() {
                        if (!isDestroy) {
                            val contentTranslate = StringBuilder()
                            val alignString = StringBuilder()
                            if (stringMap.size() > 0) {
                                var isDangerous = false
                                for (i in 0 until stringMap.size()) {
                                    //译文内容拼接
                                    val mTextTransNewRes = stringMap[i]
                                    if(i > 0){
                                        contentTranslate.append(" ")
                                    }
                                    contentTranslate.append(mTextTransNewRes.toText?:"")
                                    isDangerous = isDangerous || mTextTransNewRes.isDanger

                                    //双语对照内容拼接，按顺序
                                    mTextTransNewRes.align?.let {
                                        for (index in 0 until it.size) {
                                            val value = it[index.toString()]
                                            value?.values?.forEach { align ->
                                                if(
                                                    align.src.trim().isNotEmpty()
                                                    && align.tgt.isNotEmpty()
                                                ){
                                                    alignString.append(align.src)
                                                    alignString.append("\n")
                                                    alignString.append(align.tgt)
                                                    alignString.append("\n\n")
                                                }
                                            }
                                        }
                                    }

                                }
                                stringMap.clear()
                                val content = contentTranslate.toString()
                                val bilingual = alignString.toString()
                                if(content.trim().isEmpty()){
                                    if(isDangerous){
                                        ToastUtils.showError(R.string.trans_content_error)
                                    }else{
                                        ToastUtils.showError(R.string.trans_server_is_busy)
                                    }
                                }
                                textTranslateCallback?.onTranslateCompleted(
                                    content,
                                    bilingual,
                                    fromLang,
                                    toLang,
                                    true
                                )
                            }
                        }
                    }
                }))
        }
    }

    private fun sortByKey(req: TextTransNewReq): String{
        /**排序-拼接-md5*/
        //排序
        val map: MutableMap<String, String> = TreeMap { obj1, obj2 -> // 按照key的升序排序
            obj1?.compareTo(obj2!!)!!
        }
        map["fromLang"] = req.fromLang
        map["toLang"] = req.toLang
        map["fromText"] = req.fromText
        map["withDiff"] = req.withDiff.toString()
        map["timestamp"] = req.timestamp.toString()
        map["fromProduct"] = req.fromProduct

        val keySet: Set<String> = map.keys
        //拼接
        val it = keySet.iterator()
        var splicing = ""
        while (it.hasNext()) {
            val key = it.next()
            splicing += key + map[key]
        }
        splicing?.let {
            splicing = it + "PONYTRANS2022"
        }
        //md5
        Log.e("splicing","splicing = $splicing")
        val md5 = Md5Util.md5(splicing)
        Log.e("splicing","md5 = $md5")
        return md5
    }
}